package com.bjw.ComAssistant;

import android.widget.Toast;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidParameterException;

import com.bjw.bean.ComBean;

import android_serialport_api.SerialPort;

/**
 * @author xpgk xh
 * @date 2024-11-01
 */
public abstract class SerialHelper {
    // 协控装置最大数据长度
    private static final int READ_BUFFER_SIZE = 256;
    // 默认波特率
    private static final int BASE_BAUD_RATE = 9600;

    private SerialPort mSerialPort;
    private InputStream mInputStream;
    private ReadThread mReadThread;
    private SendThread mSendThread;
    /**
     * 串口号
     */
    private String sPort;
    /**
     * 波特率
     */
    private int iBaudRate = BASE_BAUD_RATE;
    /**
     * 串口是否打开
     */
    private boolean _isOpen = false;
    /**
     * 自动发送数据，默认0x30
     */
    private byte[] _bLoopData = new byte[]{0x30};
    /**
     * 自动发送时间间隔，单位ms。默认500
     */
    private int iDelay = 500;

    public SerialHelper(String sPort, int iBaudRate) {
        this.sPort = sPort;
        this.iBaudRate = iBaudRate;
    }

    public SerialHelper(String sPort, String sBaudRate) {
        this(sPort, Integer.parseInt(sBaudRate));
    }

    public SerialHelper(String sPort) {
        this(sPort, BASE_BAUD_RATE);
    }

    public SerialHelper() {
    }

    /**
     * 打开串口，初始化参数
     *
     * @param sPort     串口号
     * @param iBaudRate 波特率
     * @throws SecurityException
     * @throws IOException
     * @throws InvalidParameterException
     */
    public void open(String sPort, int iBaudRate) throws SecurityException, IOException, InvalidParameterException {
        this.sPort = sPort;
        this.iBaudRate = iBaudRate;
        this.open();
    }

    /**
     * 打开串口，初始化参数
     *
     * @throws SecurityException
     * @throws IOException
     * @throws InvalidParameterException
     */
    public void open() throws SecurityException, IOException, InvalidParameterException {
        mSerialPort = new SerialPort(new File(sPort), iBaudRate, 0);
        mInputStream = mSerialPort.getInputStream();
        // 创建并启动读取线程
        mReadThread = new ReadThread();
        mReadThread.start();
        // 创建自动发送线程，但先设置暂停标志，等待自动发送启动后自动恢复运行
        mSendThread = new SendThread();
        mSendThread.setSuspendFlag();
        mSendThread.start();
        _isOpen = true;
    }

    /**
     * 关闭串口，销毁资源
     */
    public void close() {
        if (mReadThread != null) {// 销毁读取线程
            mReadThread.interrupt();
        }
        if (mSendThread != null) {// 销毁自动发送线程
            mSendThread.setSuspendFlag();
            mSendThread.interrupt();
        }
        if (mSerialPort != null) {// 关闭串口
            mSerialPort.close();
            mSerialPort = null;
        }
        _isOpen = false;
    }

    /**
     * 发送数据
     *
     * @param bOutArray
     */
    public void send(byte[] bOutArray) {
        try {
            mSerialPort.getOutputStream().write(bOutArray);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送16进制数据
     *
     * @param sHex
     */
    public void sendHex(String sHex) {
        send(HexUtil.hexStringToBytes(sHex));
    }

    /**
     * 发送文本数据
     *
     * @param sTxt
     */
    public void sendTxt(String sTxt) {
        send(sTxt.getBytes());
    }

    /**
     * 启动自动发送线程
     */
    public void startAutoSend() {
        if (mSendThread != null) {
            mSendThread.setResume();
        }
    }

    /**
     * 启动自动发送线程
     *
     * @param _bLoopData 自动发送的二进制数据
     * @param iDelay     自动发送时间间隔，单位ms
     */
    public void startAutoSend(byte[] _bLoopData, int iDelay) {
        this._bLoopData = _bLoopData;
        this.iDelay = iDelay;
        startAutoSend();
    }

    /**
     * 启动自动发送线程
     *
     * @param sLoopData 自动发送的文本数据或16进制数据，根据bTxt判断
     * @param bTxt      true:sLoopData为文本数据，自动转换为16进制数据发送；false:sLoopData为16进制数据，自动去掉空格再发送
     * @param iDelay    自动发送时间间隔，单位ms
     */
    public void startAutoSend(String sLoopData, boolean bTxt, int iDelay) {
        byte[] _bLoopData = bTxt ? sLoopData.getBytes() : HexUtil.hexStringToBytes(sLoopData);
        startAutoSend(_bLoopData, iDelay);
    }

    /**
     * 暂停自动发送线程
     */
    public void stopAutoSend() {
        if (mSendThread != null) {
            mSendThread.setSuspendFlag();
        }
    }

    /**
     * 接收数据线程
     */
    private class ReadThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (!isInterrupted()) {
                try {
                    if (mInputStream == null) return;

                    byte[] buffer = new byte[READ_BUFFER_SIZE];
                    int size = mInputStream.read(buffer);
                    if (size > 0) {
                        onDataReceived(new ComBean(sPort, buffer, size));
                    }
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } catch (Throwable e) {
                    e.printStackTrace();
                    showErrMsg("ReadThread：" + e.getMessage());
                }
            }
        }
    }

    /**
     * 自动发送数据线程
     */
    private class SendThread extends Thread {
        /**
         * 线程暂停标志
         */
        public boolean suspendFlag = true;

        @Override
        public void run() {
            super.run();
            while (!isInterrupted()) {
                synchronized (this) {
                    while (suspendFlag) {// 线程暂停，等待
                        try {
                            wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                send(getbLoopData());// 发送自动发送数据
                try {
                    Thread.sleep(iDelay);// 等待延时
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        /**
         * 暂停线程
         */
        public void setSuspendFlag() {
            this.suspendFlag = true;
        }

        /**
         * 恢复线程
         */
        public synchronized void setResume() {
            this.suspendFlag = false;
            notify();
        }
    }

    /**
     * 接收数据处理抽象方法
     *
     * @param ComRecData 接收到的数据
     */
    protected abstract void onDataReceived(ComBean ComRecData);

    protected abstract void showErrMsg(String msg);

    // region 设置相关参数方法

    public boolean setPort(String sPort) {
        if (_isOpen) {
            return false;
        } else {
            this.sPort = sPort;
            return true;
        }
    }

    public boolean setBaudRate(int iBaud) {
        if (_isOpen) {
            return false;
        } else {
            iBaudRate = iBaud;
            return true;
        }
    }

    public boolean setBaudRate(String sBaud) {
        int iBaud = Integer.parseInt(sBaud);
        return setBaudRate(iBaud);
    }

    public void setbLoopData(byte[] bLoopData) {
        this._bLoopData = bLoopData;
    }

    public void setTxtLoopData(String sTxt) {
        this._bLoopData = sTxt.getBytes();
    }

    public void setHexLoopData(String sHex) {
        this._bLoopData = HexUtil.hexStringToBytes(sHex);
    }

    public void setiDelay(int iDelay) {
        this.iDelay = iDelay;
    }

    // endregion

    // region 获取相关参数方法

    public String getPort() {
        return sPort;
    }

    public int getBaudRate() {
        return iBaudRate;
    }

    public boolean isOpen() {
        return _isOpen;
    }

    public byte[] getbLoopData() {
        return _bLoopData;
    }

    public int getiDelay() {
        return iDelay;
    }

    // endregion

}